package com.hzw.saas.service.group.service;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.hzw.saas.api.group.IGroupLogService;
import com.hzw.saas.api.group.IGroupMemberReviewService;
import com.hzw.saas.api.group.IGroupMemberService;
import com.hzw.saas.api.group.IGroupService;
import com.hzw.saas.api.group.bo.GroupBo;
import com.hzw.saas.api.group.bo.GroupLogBo;
import com.hzw.saas.api.group.bo.GroupMemberBo;
import com.hzw.saas.api.group.bo.GroupMemberRoleBo;
import com.hzw.saas.api.group.enums.GroupMemberStatus;
import com.hzw.saas.api.group.event.*;
import com.hzw.saas.api.group.query.GroupMsgQuery;
import com.hzw.saas.api.group.query.GroupQuery;
import com.hzw.saas.api.group.query.GroupUQuery;
import com.hzw.saas.api.group.query.UserInviteQuery;
import com.hzw.saas.api.msg.IMsgOperationService;
import com.hzw.saas.api.msg.IMsgService;
import com.hzw.saas.api.msg.bo.MsgActionBo;
import com.hzw.saas.api.msg.bo.MsgOperationBo;
import com.hzw.saas.api.msg.enums.MsgCode;
import com.hzw.saas.api.msg.query.*;
import com.hzw.saas.api.user.IUserAccountService;
import com.hzw.saas.api.user.IUserProfileService;
import com.hzw.saas.api.user.bo.UserProfileBO;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.config.util.PageUtils;
import com.hzw.saas.common.util.IdWorker;
import com.hzw.saas.common.util.Json;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.service.group.mapper.GroupMapper;
import com.hzw.saas.service.group.mapper.GroupMemberMapper;
import com.hzw.saas.service.group.mapper.GroupMemberReviewMapper;
import com.hzw.saas.service.group.mapper.GroupMemberRoleRefMapper;
import com.hzw.saas.service.group.model.Group;
import com.hzw.saas.service.group.model.GroupMember;
import com.hzw.saas.service.group.model.GroupMemberReview;
import com.hzw.saas.service.group.model.GroupMemberRoleRef;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 用户组表 服务实现类
 * </p>
 *
 * @author sonam
 * @since 2020-12-23
 */
@Slf4j
@RequiredArgsConstructor
@Service("groupServiceImpl")
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements IGroupService, IService<Group> {
    private static final String GROUP_CACHE_NAME = "group";

    private final ApplicationEventPublisher applicationEventPublisher;

    @Resource(name = "userAccountServiceImpl")
    private IUserAccountService userAccountService;
    @Resource(name = "userProfileServiceImpl")
    private IUserProfileService userProfileService;
    @Resource(name = "msgOperationServiceImpl")
    private IMsgOperationService msgOperationService;
    @Resource(name = "msgServiceImpl")
    private IMsgService msgService;

    @Resource(name = "groupMemberReviewServiceImpl")
    private IGroupMemberReviewService groupMemberReviewService;
    @Resource(name = "groupMemberServiceImpl")
    private IGroupMemberService groupMemberService;
    @Resource(name = "groupLogServiceImpl")
    private IGroupLogService groupLogService;

    private final GroupMemberReviewMapper groupMemberReviewMapper;
    private final GroupMemberRoleRefMapper memberRoleRefMapper;
    private final GroupMemberMapper groupMemberMapper;
    private final GroupMapper groupMapper;

    private final ApplicationEventPublisher publisher;
    private final MapperFacade mapperFacade;
    private final IdWorker idWorker;

    @Resource
    private IGroupService self;

    @Override
    public boolean doesExist(String groupId) {
        return self.getGroupById(groupId) != null;
    }

    @Override
    @Cacheable(cacheNames = GROUP_CACHE_NAME, key = "#groupId")
    public GroupBo getGroupById(String groupId) {
        return mapperFacade.map(getById(groupId), GroupBo.class);
    }

    @Override
    public boolean doesExist(String userId, String groupName) {
        return this.count(Wrappers.<Group>lambdaQuery()
            .eq(Group::getGroupName, groupName)
            .eq(Group::getOwnerId, userId)) > 0;
    }

    @Override
    public boolean tryGetGroup(String userId, String groupId) {
        GroupBo group = self.getGroupById(groupId);
        return group != null && Objects.equals(group.getOwnerId(), userId);
    }

    @Override
    @CacheEvict(cacheNames = GROUP_CACHE_NAME, key = "#group.groupId")
    public boolean updateGroup(GroupUQuery group, String userId) {
        Group groupNew = mapperFacade.map(group, Group.class);

        Group existGroup = this.getOne(Wrappers.<Group>lambdaQuery()
            .eq(Group::getGroupName, groupNew.getGroupName()));

        AssertUtil.assertThrow("修改群组失败，已存在该群组名称",
            Objects.nonNull(existGroup)
                && !Objects.equals(existGroup.getGroupId(), groupNew.getGroupId())
                && Objects.equals(existGroup.getOwnerId(), userId));

        // 群组更新事件
        GroupBo groupBo = new GroupBo();
        groupBo.setGroupId(groupNew.getGroupId());
        groupBo.setOwnerId(userId);
        groupBo.setGroupName(groupNew.getGroupName());
        applicationEventPublisher.publishEvent(new UpdateGroupEvent(groupBo));
        return this.updateById(groupNew);
    }

    @Override
    @Transactional
    @CachePut(cacheNames = GROUP_CACHE_NAME, key = "#result.groupId")
    public GroupBo submitGroup(GroupQuery groupParam, String userId) {
        AssertUtil.assertThrow("用户不存在: " + userId, userAccountService.getAccount(userId) == null);
        AssertUtil.assertThrow("群组已存在", self.doesExist(userId, groupParam.getGroupName()));
        Group group = initGroup(groupParam, userId);
        this.save(group);
        if (log.isDebugEnabled()) log.debug("add group: " + Json.toJsonString(group));
        // 将自己添加到该群组中,并设置为群主
        groupMemberService.memberJoinGroup(group.getGroupId(), userId, "1");
        // 提交群组创建事件
        applicationEventPublisher.publishEvent(new GroupCreateEvent(MapperUtil.nf().map(group, GroupBo.class)));
        return mapperFacade.map(group, GroupBo.class);
    }

    @Override
    public IPage<GroupBo> searchGroupByUserAndGroupName(PageParam pageParam, String userId, String groupName) {
        AssertUtil.assertThrow("搜索群组失败, 请输入群组名称进行搜索", StringUtil.isBlank(groupName));
        /** 当前用户加入的群组ID集合*/
        List<String> joinGroupIds = groupMemberService.getGroupIdListByUserId(userId);
        return PageUtils.convert(this.page(pageParam.convert(), Wrappers.<Group>lambdaQuery()
            .notIn(CollectionUtils.isNotEmpty(joinGroupIds), Group::getGroupId, joinGroupIds)
            .like(Group::getGroupName, groupName)), GroupBo.class);
    }

    private Group initGroup(GroupQuery groupParam, String userId) {
        Group group = mapperFacade.map(groupParam, Group.class);

        group.setCreateDate(new Date());
        group.setOwnerId(userId);
        group.setGroupId(String.valueOf(idWorker.nextId()));

        return group;
    }

    @Override
    @CacheEvict(cacheNames = GROUP_CACHE_NAME, key = "#groupId")
    @Transactional(rollbackFor = Exception.class)
    public boolean delGroup(String groupId) {
        List<Group> list = this.lambdaQuery().eq(Group::getGroupId, groupId).list();
        /** 删除成员表的群组关系*/
        groupMemberMapper.delete(Wrappers.<GroupMember>lambdaQuery()
            .eq(GroupMember::getGroupId, groupId));
        /** 审核表也删除*/
        groupMemberReviewMapper.delete(Wrappers.<GroupMemberReview>lambdaQuery()
            .eq(GroupMemberReview::getGroupId, groupId));
        /** 删除群组消息*/
        msgService.deleteGroupMsg(Arrays.asList(groupId));
        /**
         * 发送事件给监听线程，删除聊天群组
         */
        if (CollectionUtils.isNotEmpty(list)){
            applicationEventPublisher.publishEvent(new GroupDeleteEvent(MapperUtil.nf().map(list.get(0), GroupBo.class)));
        }
        return this.removeById(groupId);
    }

    @Override
    @Transactional
    public void requestJoinGroup(String userId, String groupId) {
        /** 判断该群组是否存在*/
        GroupBo groupDto = self.getGroupById(groupId);
        AssertUtil.assertThrow("申请加入群组失败, 当前群组不存在", Objects.isNull(groupDto));

        /** 请求加入群组前，先判断当前登录的用户是否已加入*/
        AssertUtil.assertThrow("请求加入群组失败，该用户已加入此群组",
            groupMemberService.tryJoinGroup(userId, groupId));

        /** 判断审核表中该条记录是否有效, 无效则删除,有效则不让继续申请*/
        GroupMemberStatus groupMemberStatus = groupMemberReviewService.getGroupMemberStatus(userId, groupId, 0);
        AssertUtil.assertThrow("已申请加入该群组，请等待群主审核", groupMemberStatus == GroupMemberStatus.NORMAL);

        /** 申请加入群组，首先往审核表中插入一条记录(用户主动申请加入群组)*/
        if (groupMemberStatus == GroupMemberStatus.INVALID) {
            groupMemberReviewService.deleteGroupMemberReview(userId, groupId, 0);
        }
        GroupMemberReview groupMemberReview = initGroupMemberReview(userId, groupId, 0);
        groupMemberReviewMapper.insert(groupMemberReview);

        /** 向消息表中查一条，哪一个用户申请加入群组的群组消息*/
        MsgGroupQuery msgGroupParam = new MsgGroupQuery();
        msgGroupParam.setMsg(
            String.format("【realName{%s##%s}】请求加入群组【groupName{%s##%s}】",
                userId,
                getUserRealName(userId),
                groupDto.getGroupId(), getGroupName(groupId)));
        msgGroupParam.setFrom(groupId); // 申请的群组id
        msgGroupParam.setTo(groupDto.getOwnerId()); // 申请的群主id

        /** 构造业务，写死*/
        List<MsgActionBo> msgActionDtoList = new ArrayList<>();
        GroupMsgQuery groupMsgParam1 = new GroupMsgQuery("", userId, groupId, 1);
        Map<String, Object> data1 = mapperFacade.map(groupMsgParam1, Map.class);
        msgActionDtoList.add(new MsgActionBo(
            data1, "put", "/group/invite/reply", "通过"));
        GroupMsgQuery groupMsgParam2 = new GroupMsgQuery("", userId, groupId, 2);
        Map<String, Object> data2 = mapperFacade.map(groupMsgParam2, Map.class);
        msgActionDtoList.add(new MsgActionBo(
            data2, "put", "/group/invite/reply", "拒绝"));
        msgGroupParam.setMsgActionDtoList(msgActionDtoList);

        msgService.addMsg(msgGroupParam);
    }

    @Override
    @Transactional
    public void inviteUserJoinGroup(String userId, String groupId) {
        /** 邀请用户加入群组前,判断该用户是否已加入*/
        AssertUtil.assertThrow("邀请用户失败,已加入该群组", groupMemberService.tryJoinGroup(userId, groupId));

        /** 判断审核表中该条记录是否有效, 无效则删除,有效则不让继续申请*/
        GroupMemberStatus groupMemberStatus = groupMemberReviewService.getGroupMemberStatus(userId, groupId, 1);
        AssertUtil.assertThrow("已邀请该用户,请等待用户接受", groupMemberStatus == GroupMemberStatus.NORMAL);

        /** 邀请用户加入群组，首先往审核表中插入一条记录(群组主动邀请用户加入)*/
        if (groupMemberStatus == GroupMemberStatus.INVALID) {
            groupMemberReviewService.deleteGroupMemberReview(userId, groupId, 1);
        }
        GroupMemberReview groupMemberReview = initGroupMemberReview(userId, groupId, 1);
        groupMemberReviewMapper.insert(groupMemberReview);

        GroupBo groupBo = self.getGroupById(groupId);
        AssertUtil.assertThrow("邀请用户失败,群组不存在", Objects.isNull(groupBo));

        /** 向用户发送一条消息*/
        MsgUserQuery msgUserParam = new MsgUserQuery();
        msgUserParam.setTitle("群组邀请");
        msgUserParam.setFrom(groupBo.getOwnerId());
        msgUserParam.setTo(userId);
        msgUserParam.setMsg(String.format("用户【realName{%s##%s}】邀请您加入【groupName{%s##%s}】",
            groupBo.getOwnerId(), getUserRealName(groupBo.getGroupId()),
            groupBo.getGroupId(), getGroupName(groupBo.getGroupId())));
        ArrayList<MsgActionBo> msgActionDtoList = new ArrayList<>();
        msgUserParam.setMsgActionDtoList(msgActionDtoList);

        UserInviteQuery userInviteParam = new UserInviteQuery("", groupId, userId, 1);
        Map<String, Object> data1 = mapperFacade.map(userInviteParam, Map.class);
        msgActionDtoList.add(new MsgActionBo(
            data1, "put", "/user/invite/reply", "接受"));

        UserInviteQuery userInviteParam2 = new UserInviteQuery("", groupId, userId, 2);
        Map<String, Object> data2 = mapperFacade.map(userInviteParam2, Map.class);
        msgActionDtoList.add(new MsgActionBo(
            data2, "put", "/user/invite/reply", "拒绝"));

        msgService.addMsg(msgUserParam);
    }

    /**
     * 生成一条用户群组加入审核记录
     *
     * @param userId
     * @param groupId
     * @return
     */
    private GroupMemberReview initGroupMemberReview(String userId, String groupId, int type) {
        GroupMemberReview groupMemberReview = new GroupMemberReview();
        groupMemberReview.setDate(new Date());
        /** 审核有效期默认3天*/
        groupMemberReview.setExpireDate(DateUtil.offsetDay(new Date(), 3));
        groupMemberReview.setUserId(userId);
        groupMemberReview.setGroupId(groupId);
        groupMemberReview.setId(idWorker.nextId());
        groupMemberReview.setType(type);
        return groupMemberReview;
    }


    @Override
    public IPage<GroupMemberRoleBo> getAllGroupAndOther(IPage page, String userId) {
        IPage<GroupMemberRoleBo> groupDtoList = groupMapper.getAllGroupAndOtherByUserId(page, userId);
        return groupDtoList;
    }

    /**
     * 群主同意用户邀请
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String confirmMember(GroupMsgQuery groupMsgParam) {
        String groupId = groupMsgParam.getGroupId();
        String userId = groupMsgParam.getUserId();
        Integer type = groupMsgParam.getType();
        String msgOperationId = groupMsgParam.getMsgOperationId();

        /** 查询当前消息操作是否存在*/
        MsgOperationBo msgOperationBo = msgOperationService.getMsgOperatorById(msgOperationId);
        AssertUtil.assertThrow("确认用户加入/拒绝群组失败，不能操作当前消息",
            Objects.isNull(msgOperationBo) || CollectionUtils.isEmpty(msgOperationBo.getMsgActionDtoList()));

        /** 查询当前消息操作是否处理*/
        AssertUtil.assertThrow("该条消息已处理，请刷新页面",
            !StringUtil.isBlank(msgOperationBo.getMsgText()) && MsgCode.instance(msgOperationBo.getMsgCode()) != null);

        /** 验证msgOperator 是否有效*/
        List<MsgActionBo> msgActionList = msgOperationBo.getMsgActionDtoList();
        List<GroupMsgQuery> groupMsgParamList = new ArrayList<>();
        msgActionList.forEach(msgActionDto -> {
            groupMsgParamList.add(mapperFacade.map(msgActionDto.getData(), GroupMsgQuery.class));
        });
        /** 验证传递过来的信息是否和数据库的一致*/
        AssertUtil.assertThrow("确认用户加入/拒绝群组失败，无效的群组操作参数", !groupMsgParamList.contains(groupMsgParam));

        /** 检查申请加入群组消息是否有效，主要看消息审核表中的数据是否存在，或者过期 */
        GroupMemberStatus groupMemberStatus = groupMemberReviewService.getGroupMemberStatus(userId, groupId, 0);
        if (groupMemberStatus == GroupMemberStatus.NO_EXIST) {
            updateMsgOperation(msgOperationId, MsgCode.ERROR, "无效");
            return "操作无效";
        }

        if (groupMemberStatus == GroupMemberStatus.INVALID) {
            groupMemberReviewService.deleteGroupMemberReview(userId, groupId, 0);
            /** 群组成员加入审核 >> 不存在/过期 */
            updateMsgOperation(msgOperationId, MsgCode.ERROR, "失效");
            return "操作过期";
        }

        /** 检查当前用户是否在该群组中*/
        if (groupMemberService.tryJoinGroup(userId, groupId)) {
            groupMemberReviewService.deleteGroupMemberReview(userId, groupId, 0);
            updateMsgOperation(msgOperationId, MsgCode.ERROR, "已加入");
            return "确认用户加入/拒绝群组失败，该用户已加入该群组";
        }

        /** 群组同意成员加入群组 */
        if (type == 1) {
            String successJoinUserMsg = String.format("你已成功加入【groupName{%s}】,快去和小伙伴们一起开启科研之旅吧!", groupId);
            String successJoinGroupMsg = String.format("新伙伴【realName{%s}】已成功加入【groupName{%s}】", userId, groupId);

            memberJoinGroup(groupId, userId, msgOperationId, successJoinGroupMsg, successJoinUserMsg);
        } else if (type == 2) {
            /** 群组主动拒绝成员加入群组 */
            /** 发送一条系统消息到用户，通知群主您不同意加入*/
            MsgQuery msgQuery = MsgSystemQuery.instance("加入群组失败",
                String.format("【realName{%s##%s}】拒绝您加入他的群组【groupName{%s##%s}】",
                    userId, getUserRealName(userId), groupId, getGroupName(groupId)),
                userId);
            /** 发送消息*/
            msgService.addMsg(msgQuery);
            /** 更新msgOperator信息*/
            updateMsgOperation(msgOperationId, MsgCode.FAIL, "已拒绝");
        } else {
            AssertUtil.assertThrow("确认成员加入群组失败，无效的操作类型", true);
        }

        /** 操作成功，删除审核表记录*/
        groupMemberReviewMapper.delete(Wrappers.<GroupMemberReview>lambdaQuery()
            .eq(GroupMemberReview::getGroupId, groupId)
            .eq(GroupMemberReview::getUserId, userId)
            .eq(GroupMemberReview::getType, 0));

        return null;
    }

    /**
     * 用户同意群组邀请
     */
    @Override
    @Transactional
    public String confirmGroup(UserInviteQuery userInviteParam) {
        String groupId = userInviteParam.getGroupId();
        String userId = userInviteParam.getUserId();
        Integer type = userInviteParam.getType();
        String msgOperationId = userInviteParam.getMsgOperationId();

        /** 查询当前消息操作是否存在*/
        MsgOperationBo msgOperation = msgOperationService.getMsgOperatorById(msgOperationId);
        AssertUtil.assertThrow("确认/拒绝加入群组，不能操作当前消息",
            Objects.isNull(msgOperation) || CollectionUtils.isEmpty(msgOperation.getMsgActionDtoList()));
        /** 查询当前消息操作是否处理*/
        AssertUtil.assertThrow("该条消息已处理，请刷新页面",
            !StringUtil.isBlank(msgOperation.getMsgText()) && MsgCode.instance(msgOperation.getMsgCode()) != null);

        /** 验证msgOperator 是否有效*/
        List<MsgActionBo> msgActionList = msgOperation.getMsgActionDtoList();
        List<UserInviteQuery> userInviteParams = new ArrayList<>();
        msgActionList.forEach(msgActionDto -> {
            userInviteParams.add(mapperFacade.map(msgActionDto.getData(), UserInviteQuery.class));
        });
        /** 验证传递过来的信息是否和数据库的一致*/
        AssertUtil.assertThrow("接受/拒绝群组邀请失败，无效的参数", !userInviteParams.contains(userInviteParam));

        /** 检查申请加入群组消息是否有效，主要看消息审核表中的数据是否存在，或者过期 */
        GroupMemberStatus groupMemberStatus = groupMemberReviewService.getGroupMemberStatus(userId, groupId, 1);
        if (groupMemberStatus == GroupMemberStatus.NO_EXIST) {
            updateMsgOperation(msgOperationId, MsgCode.ERROR, "失效");
            return "操作无效";
        }

        if (groupMemberStatus == GroupMemberStatus.INVALID) {
            groupMemberReviewService.deleteGroupMemberReview(userId, groupId, 1);
            /** 群组成员加入审核 >> 不存在/过期 */
            updateMsgOperation(msgOperationId, MsgCode.ERROR, "失效");
            return "操作过期";
        }

        /** 检查当前用户是否在该群组中*/
        if (groupMemberService.tryJoinGroup(userId, groupId)) {
            groupMemberReviewService.deleteGroupMemberReview(userId, groupId, 1);
            updateMsgOperation(msgOperationId, MsgCode.ERROR, "已加入");
            return "用户同意群组邀请失败,当前用户已加入该群组";
        }

        GroupBo groupDto = self.getGroupById(groupId);
        /** 用户同意加入群组 */
        if (type == 1) {
            String successJoinGroupMsg = String.format("新伙伴【realName{%s##%s}】已成功加入【groupName{%s##%s}】", userId, getUserRealName(userId), groupId, getGroupName(groupId));
            String successJoinUserMsg = String.format("您已成功加入【groupName{%s##%s}】,快去和小伙伴们一起开启科研之旅吧!", groupId, getGroupName(groupId));

            memberJoinGroup(groupId, userId, msgOperationId, successJoinGroupMsg, successJoinUserMsg);
        } else if (type == 2) {
            /** 用户主动拒绝加入群组 */
            /** 发送一条系统消息到群主用户，通知群主用户拒绝加入群组*/
            MsgQuery msgParam = MsgSystemQuery.instance("用户拒绝加入群组",
                String.format("【realName{%s##%s}】拒绝加入您的群组【groupName{%s##%s}】",
                    userId,
                    getUserRealName(userId),
                    groupId, getGroupName(groupId)),
                groupDto.getOwnerId());
            /** 发送消息*/
            msgService.addMsg(msgParam);
            /** 更新msgOperator信息*/
            updateMsgOperation(msgOperationId, MsgCode.FAIL, "已拒绝");
        } else {
            AssertUtil.assertThrow("用户接受/拒绝群组失败，无效的操作类型", true);
        }

        /** 操作成功，删除审核表记录*/
        groupMemberReviewMapper.delete(Wrappers.<GroupMemberReview>lambdaQuery()
            .eq(GroupMemberReview::getGroupId, groupId)
            .eq(GroupMemberReview::getUserId, userId)
            .eq(GroupMemberReview::getType, 1));

        return null;
    }

    /**
     * 用户加入群组
     *
     * @param groupId
     * @param userId
     * @param msgOperationId
     * @param successJoinGroupMsg
     * @param successJoinUserMsg
     */
    private void memberJoinGroup(String groupId, String userId, String msgOperationId, String successJoinGroupMsg, String successJoinUserMsg) {
        /** 添加成员到群组 */
        groupMemberService.memberJoinGroup(groupId, userId, "2");
        List<Group> list = this.lambdaQuery().eq(Group::getGroupId, groupId).list();
        if (CollectionUtils.isNotEmpty(list)){
            /** 发送成员进入群组事件*/
            applicationEventPublisher.publishEvent(new MemberJoinAgreementEvent(groupId, userId,list.get(0).getOwnerId()));

        }
        /** 发送一条系统消息到用户，通知该用户已加入群组*/
        MsgQuery msgQuery = MsgSystemQuery.instance("加入群组成功", successJoinUserMsg, userId);

        /** 更新msgOperator信息*/
        updateMsgOperation(msgOperationId, MsgCode.SUCCESS, "已同意");

        /** 向整个群组发送消息*/
        MsgGroupQuery msgGroupParam1 = new MsgGroupQuery();
        msgGroupParam1.setTo(groupId);
        msgGroupParam1.setFrom(groupId);
        msgGroupParam1.setMsg(successJoinGroupMsg);

        msgService.addMsg(msgGroupParam1);
        msgService.addMsg(msgQuery);
    }


    private void updateMsgOperation(String msgOperationId, MsgCode msgCode, String msg) {
        MsgOperationUQuery msgOperationUQuery = new MsgOperationUQuery();
        msgOperationUQuery.setMsgCode(msgCode.code());
        msgOperationUQuery.setMsgText(msg);
        msgOperationUQuery.setUpdateDate(new Date());
        msgOperationUQuery.setId(msgOperationId);
        msgOperationService.updateMsgOperatorById(msgOperationUQuery);
    }

    @Override
    @Transactional
    public void leaveGroup(String userId, String groupId) {
        GroupMember groupMember = groupMemberMapper.selectOne(Wrappers.<GroupMember>lambdaQuery()
            .eq(GroupMember::getGroupId, groupId)
            .eq(GroupMember::getUserId, userId));

        AssertUtil.assertThrow("离开群组失败，你不在该群组中", Objects.isNull(groupMember));

        String memberId = groupMember.getMemberId();
        GroupMemberRoleRef mrr = memberRoleRefMapper.selectOne(Wrappers.<GroupMemberRoleRef>lambdaQuery()
            .eq(GroupMemberRoleRef::getMemberId, memberId));
        AssertUtil.assertThrow("离开群组失败，你不能离开当前群组", Objects.equals("1", mrr.getRoleId()));

        // 离开群组成功
        removeMemberByGroup(groupId, memberId, userId);
    }

    @Override
    public IPage<GroupLogBo> getGroupDynamicById(IPage page, String groupId) {
        return groupLogService.pageByGroupId(page, groupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeMemberByGroup(String groupId, String memberId, String operationUserId) {
        GroupMemberRoleRef memberRoleRef = memberRoleRefMapper.selectOne(Wrappers.<GroupMemberRoleRef>lambdaQuery()
            .eq(GroupMemberRoleRef::getMemberId, memberId));
        AssertUtil.assertThrow("不能从群组从移除群主", Objects.equals("1", memberRoleRef.getRoleId()));

        GroupMemberBo groupMemberBo = groupMemberService.getById(memberId);
        AssertUtil.assertThrow("移除成员失败，移除的成员不存在", Objects.isNull(groupMemberBo));
        String userId = groupMemberBo.getUserId();

        /** 删除成员信息、删除成员表角色信息*/
        if (SqlHelper.retBool(groupMemberMapper.delete(Wrappers.<GroupMember>lambdaQuery()
            .eq(GroupMember::getMemberId, memberId)
            .eq(GroupMember::getGroupId, groupId)))
            || SqlHelper.retBool(memberRoleRefMapper.delete(Wrappers.<GroupMemberRoleRef>lambdaQuery()
            .eq(GroupMemberRoleRef::getMemberId, memberId)))) {

            /** 发一个用户离开群组的事件*/
            MemberLeaveGroupEvent memberLeaveGroupEvent = new MemberLeaveGroupEvent().setGroupId(groupId).setUserId(userId);
            publisher.publishEvent(memberLeaveGroupEvent);
//            /** 删除该用户在群组中的消息*/
//            msgService.deleteMsgByFromAndTo(groupId, userId);
//            // TODO 删除用户 tb_msg_read
//            // TODO 删除用户 tb_msg_operation

            GroupBo groupBo = self.getGroupById(groupId);

            /** 仅通知用户*/
            MsgSystemQuery msgSystemParam = new MsgSystemQuery();
            msgSystemParam.setTo(userId);
            msgSystemParam.setTitle("离开群组");

            /** 仅通知群主*/
            MsgGroupQuery msgGroupParam = new MsgGroupQuery();
            msgGroupParam.setFrom(groupBo.getGroupId());
            msgGroupParam.setTo(groupBo.getOwnerId());

            /** 是否通知群组其他成员，该用户已离开群组*/
            // TODO

            /** 群组主动踢 OR 成员主动离开*/
            if (Objects.equals(userId, operationUserId)) {
                /** 成员主动离开*/
                /** 发送给群主的消息内容*/
                msgGroupParam.setMsg(String.format("【realName{%s##%s}】已离开你的群组【groupName{%s##%s}】", userId, getUserRealName(userId), groupId, getGroupName(groupId)));
                /** 发送给用户的消息内容*/
                msgSystemParam.setMsg(String.format("很遗憾,您已离开群组【groupName{%s##%s}】", groupId, getGroupName(groupId)));
                /** 成员主动离开事件*/
                applicationEventPublisher.publishEvent(new MemberLeaveGroupEvent().setGroupId(groupId).setUserId(userId));
            } else {
                /** 发送给群主的消息内容*/
                msgGroupParam.setMsg(String.format("你已将成员【realName{%s##%s}】从群组【groupName{%s##%s}】移除", userId, getUserRealName(userId), groupId, getGroupName(groupId)));
                /** 发送给用户的消息内容*/
                msgSystemParam.setMsg(String.format("很遗憾,群组【groupName{%s##%s}】移除了您", groupId, getGroupName(groupId)));
                /** 群组踢人事件*/
                applicationEventPublisher.publishEvent(new DeleteGroupMemberEvent(groupBo,memberId,operationUserId));
            }
            msgService.addMsg(msgGroupParam);
            msgService.addMsg(msgSystemParam);
            return;
        }

        AssertUtil.assertThrow("移除失败，群组成员不存在!", true);
    }

    @Override
    public List<GroupBo> getDefaultGroupListByUserId(String userId) {
        List<Group> groups = this.list(Wrappers.<Group>lambdaQuery().eq(Group::getOwnerId, ""));
        return mapperFacade.mapAsList(groups, GroupBo.class);
    }

    @Override
    public List<GroupBo> findNeedRefresh() {
        List<Group> list = this.lambdaQuery().ne(Group::getGroupId, "1000").list();
        if (CollectionUtils.isNotEmpty(list)){
            return MapperUtil.nf().mapAsList(list,GroupBo.class);
        }
        return null;
    }

    private String getGroupName(String groupId) {
        GroupBo groupBo = self.getGroupById(groupId);
        return Objects.isNull(groupBo) ? "null" : groupBo.getGroupName();
    }

    private String getUserRealName(String userId) {
        UserProfileBO userProfileBO = userProfileService.get(userId);
        return Objects.isNull(userProfileBO) ? "null" : userProfileBO.getRealName();
    }

}
